package com.xfcy.blog.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xfcy.blog.common.R;
import com.xfcy.blog.common.constant.RedisConstant;
import com.xfcy.blog.common.constant.SqlConstant;
import com.xfcy.blog.config.satoken.MySaTokenListener;
import com.xfcy.blog.dto.SystemUserDTO;
import com.xfcy.blog.entity.Menu;
import com.xfcy.blog.entity.UserAuth;
import com.xfcy.blog.entity.WebConfig;
import com.xfcy.blog.mapper.UserAuthMapper;
import com.xfcy.blog.mapper.UserMapper;
import com.xfcy.blog.entity.User;
import com.xfcy.blog.service.*;
import com.xfcy.blog.strategy.context.FileUploadStrategyContext;
import com.xfcy.blog.utils.BCryptUtils;
import com.xfcy.blog.utils.BeanCopyUtil;
import com.xfcy.blog.vo.LoginUserVO;
import com.xfcy.blog.vo.MenuVO;
import com.xfcy.blog.vo.SystemUserVO;
import com.xfcy.blog.vo.UserVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统管理-用户基础信息表(User)表服务实现类
 *
 * @author 晓风残月Lx
 * @since 2023-04-09 11:03:06
 */
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Resource
    private MenuService menuService;

    @Resource
    private UserAuthMapper userAuthMapper;

    @Resource
    private WebConfigService webConfigService;

    @Resource
    private FileUploadStrategyContext fileUploadStrategyContext;

    @Resource
    private SystemConfigService systemConfigService;

    @Resource
    private RedisTemplate redisTemplate;


    /**
     * 获取当前登录用户信息
     *
     * @return
     */
    @Override
    public R getCurrentUserInfo() {
        return R.success("获取当前登录用户信息成功", baseMapper.getById(StpUtil.getLoginIdAsInt()));
    }

    /**
     * 获取用户菜单
     *
     * @return
     */
    @Override
    public R getCurrentUserMenu() {
        List<Integer> menuIds = baseMapper.getMenuId(StpUtil.getLoginIdAsInt());
        List<Menu> menus = menuService.listByIds(menuIds);
        List<MenuVO> menuVOS = BeanCopyUtil.listCopy(menus, MenuVO.class);
        List<MenuVO> menuTree = menuService.listMenuTree(menuVOS);
        return R.success(menuTree);
    }

    /**
     * 获取用户
     *
     * @param pageNo
     * @param pageSize
     * @param username
     * @param loginType
     * @return
     */
    @Override
    public R listUser(Integer pageNo, Integer pageSize, String username, Integer loginType) {
        Page<UserVO> userPage = baseMapper.selectPageRecord(new Page<UserVO>(pageNo, pageSize), username, loginType);
        return R.success(userPage);
    }

    /**
     * 通过id查询用户
     *
     * @param id
     * @return
     */
    @Override
    public R selectById(Integer id) {
        SystemUserVO user = baseMapper.getById(id);
        return R.success(user);
    }

    /**
     * 更新用户
     *
     * @param systemUserDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R updateUser(SystemUserDTO systemUserDTO) {
        User user = new User();
        user.setId(systemUserDTO.getId());
        user.setUsername(systemUserDTO.getUsername());
        user.setStatus(systemUserDTO.getStatus());
        user.setRoleId(systemUserDTO.getRoleId());
        if (!"".equals(systemUserDTO.getPassword()) && !systemUserDTO.getPwd().equals(systemUserDTO.getPassword())) {
            user.setPassword(BCryptUtils.encrypt(systemUserDTO.getPassword()));
        }
        baseMapper.updateById(user);

        UserAuth userAuth = userAuthMapper.getByUserId(systemUserDTO.getId());

        // 如果是默认图片，不删除
        WebConfig config = webConfigService.getOne(new QueryWrapper<WebConfig>().select(SqlConstant.TOURIST_AVATAR).last(SqlConstant.LIMIT_ONE));

        // 判断和数据库图片是否相同，并且数据库中是否是默认头像
        if (!userAuth.getAvatar().equals(config.getTouristAvatar()) && !systemUserDTO.getAvatar().equals(userAuth.getAvatar())) {
            redisTemplate.opsForSet().remove(RedisConstant.DB_FILE_UPLOAD_IMAGES, userAuth.getAvatar());
            redisTemplate.opsForSet().add(RedisConstant.DB_FILE_UPLOAD_IMAGES, systemUserDTO.getAvatar());
        }

        userAuth.setNickname(systemUserDTO.getNickname());
        userAuth.setAvatar(systemUserDTO.getAvatar());
        userAuthMapper.updateById(userAuth);

        return R.success("修改成功！！！");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R createUser(SystemUserDTO systemUserDTO) {

        // 如果是默认图片，不删除
        WebConfig config = webConfigService.getOne(new QueryWrapper<WebConfig>().select(SqlConstant.TOURIST_AVATAR).last(SqlConstant.LIMIT_ONE));
        UserAuth userAuth = new UserAuth();
        userAuth.setEmail(systemUserDTO.getUsername());
        userAuth.setNickname(systemUserDTO.getNickname());
        if (!"".equals(systemUserDTO.getAvatar())) {
            userAuth.setAvatar(systemUserDTO.getAvatar());
            redisTemplate.opsForSet().add(RedisConstant.DB_FILE_UPLOAD_IMAGES, systemUserDTO.getAvatar());
        } else {
            userAuth.setAvatar(config.getTouristAvatar());
            // 默认头像不添加入redis
        }

        userAuthMapper.insert(userAuth);

        User user = User.builder().username(systemUserDTO.getUsername())
                .roleId(systemUserDTO.getRoleId())
                .password(BCryptUtils.encrypt(systemUserDTO.getPassword()))
                .status(systemUserDTO.getStatus())
                .userAuthId(userAuth.getId())
                .build();
        baseMapper.insert(user);

        return R.success("添加成功！！！");
    }

    /**
     * 批量删除用户
     *
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R removeUser(List<Integer> ids) {
        // redis删除图片
        List<String> deleteImage = userAuthMapper.getAvatarByIds(ids);
        redisTemplate.opsForSet().remove(RedisConstant.DB_FILE_UPLOAD_IMAGES, deleteImage.toArray());

        userAuthMapper.deleteByUserIds(ids);
        int i = baseMapper.deleteBatchIds(ids);
        return i > 0 ? R.success("删除成功！") : R.error("删除失败");
    }

    /**
     * 查看在线用户列表
     *
     * @param pageNo
     * @param pageSize
     * @param keywords
     * @return
     */
    @Override
    public R listOnlineUsers(Integer pageNo, Integer pageSize, String keywords) {
        List<LoginUserVO> loginUserVOList = MySaTokenListener.ONLINE_USERS;

        // 根据关键词过滤
        if (StringUtils.isNotBlank(keywords)) {
            loginUserVOList = MySaTokenListener.ONLINE_USERS.stream().filter(item -> item.getNickname().contains(keywords)).collect(Collectors.toList());
        }
        // 排序
        loginUserVOList.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime()));
        int fromIndex = (pageNo - 1) * pageSize;
        int toIndex = loginUserVOList.size() - fromIndex > pageSize ? fromIndex + pageSize : loginUserVOList.size();
        List<LoginUserVO> loginUserVOS = loginUserVOList.subList(fromIndex, toIndex);
        logger.info("memory用户数：{}", loginUserVOS.size());

        Map<String, Object> map = new HashMap<>();
        map.put("total", loginUserVOList.size());
        map.put("records", loginUserVOS);
        return R.success(map);
    }

    /**
     * 踢人下线
     * @param token
     * @return
     */
    @Override
    public R kick(String token) {
        logger.info("当前踢下线的用户token为:{}",token);
        StpUtil.kickoutByTokenValue(token);
        return R.success();
    }
}


